package net.cellkyborg.RSInstances;

import net.cellkyborg.server.*;

public abstract class RSMoveable extends RSObject {
	
	public RSMoveable() {
		super();
		
		resetWalkAction();
		resetWalkingQueue();
	}
	
	public int teleportToX = -1, teleportToY = -1;

	/*
	 * public static final int walkingQueueSize = 50; public int walkingQueueX[] =
	 * new int[walkingQueueSize], walkingQueueY[] = new int[walkingQueueSize];
	 * public int wQueueReadPtr = 0; // points to slot for reading from queue
	 * public int wQueueWritePtr = 0;
	 */

	// int gotoX = -1, gotoY = -1;
	public int dir1 = -1, dir2 = -1;
	boolean mapRegionDidChange = false, didTeleport = false;

	private static byte directionDeltaX[] = new byte[] { -1, 0, 1, -1, 1, -1,
			0, 1 };
	private static byte directionDeltaY[] = new byte[] { 1, 1, 1, 0, 0, -1, -1,
			-1 };

	final int directionQueueSize = 100;
	int[] directionQueue = new int[directionQueueSize];
	int[] directionQueueX = new int[directionQueueSize];
	int[] directionQueueY = new int[directionQueueSize];
	int dirWriteOffset = 0, dirReadOffset = 0;

	public boolean isRunning = false;

	int walkActionID = -1;
	stream walkActionStream = new stream(new byte[128]);

	public void processWalking() {
		mapRegionDidChange = false;
		didTeleport = false;
		dir1 = dir2 = -1;
		int[] mapRegion = getMapRegion();
		int[] location = getLocation();
		int[] currentLocation = getCurrentLocation();
		
		if (teleportToX != -1 && teleportToY != -1) {
			mapRegionDidChange = true;
			if (mapRegion[0] != -1 && mapRegion[1] != -1) {
				int relX = teleportToX - mapRegion[0] * 8;
				int relY = teleportToY - mapRegion[1] * 8;
				if (relX >= 2 * 8 && relX < 11 * 8 && relY >= 2 * 8
						&& relY < 11 * 8)
					mapRegionDidChange = false;
			}
			if (mapRegionDidChange) {
				mapRegion[0] = (teleportToX >> 3);
				mapRegion[1] = (teleportToY >> 3);
			}
			currentLocation[0] = teleportToX - 8 * (mapRegion[0] - 6);
			currentLocation[1] = teleportToY - 8 * (mapRegion[1] - 6);
			location[0] = teleportToX;
			location[1] = teleportToY;
			resetWalkingQueue();
			teleportToX = teleportToY = -1;
			didTeleport = true;
		} else {
			dir1 = getNextWalkingDirection();
			if (dir1 == -1) {
				if (walkActionID > 0) handleWalkAction();
				return;
			}
			if (isRunning) {
				dir2 = getNextWalkingDirection();
			}
			if (currentLocation[0] < 2 * 8) {
				mapRegionDidChange = true;
			} else if (currentLocation[0] >= 11 * 8) {
				mapRegionDidChange = true;
			}
			if (currentLocation[1] < 2 * 8) {
				mapRegionDidChange = true;
			} else if (currentLocation[1] >= 11 * 8) {
				mapRegionDidChange = true;
			}
			if (mapRegionDidChange) {
				mapRegion[0] = (location[0] >> 3);
				mapRegion[1] = (location[1] >> 3);
				int deltaX = (location[0] - 8 * (mapRegion[0] - 6)) - currentLocation[0];
				int deltaY = (location[1] - 8 * (mapRegion[1] - 6)) - currentLocation[1];
				currentLocation[0] += deltaX;
				currentLocation[1] += deltaY;
				for (int i = dirReadOffset - 1; i < dirWriteOffset; i++) {
					directionQueueX[i] += deltaX;
					directionQueueY[i] += deltaY;
				}
			}
		}
	}

	public void addToWalkingQueue(int x, int y) {
		/*
		 * int next = (wQueueWritePtr+1) % walkingQueueSize; if(next ==
		 * wQueueWritePtr) return; // walking queue full, silently discard the
		 * data walkingQueueX[wQueueWritePtr] = x; walkingQueueY[wQueueWritePtr] =
		 * y; wQueueWritePtr = next;
		 */
		try {
			int diffX = x - directionQueueX[dirWriteOffset - 1], diffY = y
					- directionQueueY[dirWriteOffset - 1];// 2 -2
			int max = Math.max(Math.abs(diffX), Math.abs(diffY));

			for (int i = 0; i < max; i++) {
				if (diffX < 0)
					diffX += 1;
				else if (diffX > 0)
					diffX -= 1;

				if (diffY < 0)
					diffY += 1;
				else if (diffY > 0)
					diffY -= 1;

				// System.out.println("Go from "+currentX+" "+currentY+" to "+
				// (x-diffX)+" "+(y-diffY));
				addStepToWalkingQueue(x - diffX, y - diffY);
			}

		} catch (IndexOutOfBoundsException ex) {
		}
	}

	private void addStepToWalkingQueue(int x, int y) {
		int dir = -1;

		int diffX = x - directionQueueX[dirWriteOffset - 1], diffY = y
				- directionQueueY[dirWriteOffset - 1];
		// System.out.println(diffX+" "+diffY);
		if (diffY == 1) {
			if (diffX == -1)
				dir = 0;
			else if (diffX == 0)
				dir = 1;
			else if (diffX == 1)
				dir = 2;
		} else if (diffY == 0) {
			if (diffX == -1)
				dir = 3;
			else if (diffX == 0)
				dir = -1;
			else if (diffX == 1)
				dir = 4;
		} else if (diffY == -1) {
			if (diffX == -1)
				dir = 5;
			else if (diffX == 0)
				dir = 6;
			else if (diffX == 1)
				dir = 7;
		}
		if (dirWriteOffset >= directionQueueSize)
			return;
		if (dir != -1) {
			directionQueueX[dirWriteOffset] = x;
			directionQueueY[dirWriteOffset] = y;
			directionQueue[dirWriteOffset++] = dir;
		}
		// System.out.println(dir);
	}

	private int getNextWalkingDirection() {
		/*
		 * if(wQueueReadPtr == wQueueWritePtr) return -1; // walking queue empty
		 * int dir; do { dir = direction(currentX, currentY,
		 * walkingQueueX[wQueueReadPtr], walkingQueueY[wQueueReadPtr]); if(dir ==
		 * -1) wQueueReadPtr = (wQueueReadPtr+1) % walkingQueueSize; else
		 * if((dir&1) != 0) { System.out.println("Invalid waypoint in walking
		 * queue: "+dir); resetWalkingQueue(); return -1; } } while(dir == -1 &&
		 * wQueueReadPtr != wQueueWritePtr); if(dir == -1) return -1; dir >>= 1;
		 * currentX += directionDeltaX[dir]; currentY += directionDeltaY[dir];
		 * absX += directionDeltaX[dir]; absY += directionDeltaY[dir]; return
		 * dir;
		 */
		if (dirReadOffset == dirWriteOffset)
			return -1;

		int dir = directionQueue[dirReadOffset++];

		currentLocation[0] += directionDeltaX[dir];
		currentLocation[1] += directionDeltaY[dir];
		location[0] += directionDeltaX[dir];
		location[1] += directionDeltaY[dir];

		return dir;
	}

	public void resetWalkingQueue() {
		/*
		 * wQueueReadPtr = wQueueWritePtr = 0; // properly initialize this to
		 * make the "travel back" algorithm work for(int i = 0; i <
		 * walkingQueueSize; i++) { walkingQueueX[i] = currentX;
		 * walkingQueueY[i] = currentY; }
		 */

		directionQueueX[0] = currentLocation[0];
		directionQueueY[0] = currentLocation[1];
		directionQueue[0] = -1;
		dirReadOffset = dirWriteOffset = 1;
	}

	public abstract void handleWalkAction();
	
	public void resetWalkAction() {
		walkActionID = -1;
		walkActionStream.readOffset = 0;
		walkActionStream.writeOffset = 0;
	}
}
